﻿using System;
using Validity.Rules.Decorators;

namespace Validity.Contexts
{
  public interface IMessageValidationContext<TObject, TValue>
    : IValidationContext<TObject, TValue>
  {
    IValidationContext<TObject, TValue> ReplacingMessageWith(String message);
    IValidationContext<TObject, TValue> ReplacingMessageWith(Func<String> messageFactory);
    IValidationContext<TObject, TValue> ReplacingMessageWith(Func<TValue, String> messageFactory);
    IValidationContext<TObject, TValue> ReplacingMessageWith(Func<TObject, String> messageFactory);
    IValidationContext<TObject, TValue> ReplacingMessageWith(Func<TObject, TValue, String> messageFactory);
  }

  public class MessageValidationContext<TObject, TValue>
    : ValidationContext<TObject, TValue>, IMessageValidationContext<TObject, TValue>
  {
    public MessageValidationContext()
    { }

    public MessageValidationContext(IValidationContext<TObject, TValue> context)
      : base(context)
    { }

    #region ReplacingMessageWith

    public IValidationContext<TObject, TValue> ReplacingMessageWith(String message)
    {
      Verify.False(String.IsNullOrEmpty(message));
      return ReplacingMessageWith((obj, val) => message);
    }

    public IValidationContext<TObject, TValue> ReplacingMessageWith(Func<String> messageFactory)
    {
      Verify.NotNull(messageFactory);
      return ReplacingMessageWith((obj, val) => messageFactory.Invoke());
    }

    public IValidationContext<TObject, TValue> ReplacingMessageWith(Func<TValue, String> messageFactory)
    {
      Verify.NotNull(messageFactory);
      return ReplacingMessageWith((obj, val) => messageFactory.Invoke(val));
    }

    public IValidationContext<TObject, TValue> ReplacingMessageWith(Func<TObject, String> messageFactory)
    {
      Verify.NotNull(messageFactory);
      return ReplacingMessageWith((obj, val) => messageFactory.Invoke(obj));
    }

    public IValidationContext<TObject, TValue> ReplacingMessageWith(Func<TObject, TValue, String> messageFactory)
    {
      Verify.NotNull(messageFactory);

      DecorateLastRuleWith(rule => new CustomMessageRuleDecorator<TObject, TValue>(rule, messageFactory));

      return new ValidationContext<TObject, TValue>(this);
    }

    #endregion
  }
}
